#!/usr/local/bin/perl
# edit_user.cgi
# Display a form for editing or adding a user. This can be a local user,
# or a domain mailbox user
require './virtual-server-lib.pl';
&ReadParse();
# Check access
if ($in{'dom'}) {
$d = &get_domain($in{'dom'});
&can_edit_domain($d) || &error($text{'users_ecannot'});
}
else {
&can_edit_local() || &error($text{'users_ecannot2'});
}
&can_edit_users() || &error($text{'users_ecannot'});
# Get domain and templates details
$din = $d ? &domain_in($d) : undef;
$tmpl = $d ? &get_template($d->{'template'}) : &get_template(0);
# Set user type
$user_type = $in{'type'};
# Set defaults
$form_end = 1;
@tds = ( "width=30%", "width=70%" );
# Create SSH user only form
if ($user_type eq 'ssh') {
&can_mailbox_ssh() || &error($text{'users_ecannotssh'});
&ui_print_header($din, $text{'user_createssh'}, "",
"users_explain_user_ssh");
$user = &create_initial_user($d);
print &ui_form_start("save_user.cgi", "post");
print &ui_hidden("new", 1);
print &ui_hidden("dom", $in{'dom'});
print &ui_hidden("recovery_def", 1);
print &ui_hidden('newmail_def', 1);
print &ui_hidden_table_start(
$d ? $text{'user_header_ssh'} : $text{'user_lheader'},
"width=100%", 2, "table1", 1);
# Edit mail username
print &ui_table_row(
&hlink($text{'user_user2'}, "username2_universal"),
&vui_noauto_textbox("mailuser", undef, 13).
($d ? "\@".&show_domain_name($d) : ""),
2, \@tds);
# Password cannot be edited for domain owners (because it is the
# domain pass)
$pwfield = &new_password_input("mailpass");
if (!$user->{'alwaysplain'}) {
# Option to disable
$pwfield .= "
" if ($pwfield !~ /\/table>/);
$pwfield .=
&ui_checkbox("disable", 1, $text{'user_disabled'},
$user->{'pass'} =~ /^\!/ ? 1 : 0);
}
print &ui_table_row(&hlink($text{'user_pass'}, "password"),
$pwfield,
2, \@tds);
# SSH public key for Unix user
if (&proshow()) {
print &ui_table_row(
&hlink($text{'form_sshkey'}, "sshkeynogen"),
&inline_html_pro_tip(
&ui_radio("sshkey_mode", 0,
[ [ 0, $text{'form_sshkey0'} ],
[ 2, $text{'form_sshkey2'} ] ]),
'manage-user-ssh-public-key').
"
\n".&ui_textarea("sshkey", undef, 3, 60,
undef, !$virtualmin_pro),
undef, &procell() || \@tds);
}
# Real name
print &ui_table_row(
&hlink($text{'user_real'}, "realname"),
&vui_noauto_textbox("real", $user->{'real'}, 40),
2, \@tds);
# Show SSH shell select if more than one available
my @ssh_shells = &list_available_shells_by_type('owner', 'ssh');
if (scalar(@ssh_shells) == 1) {
print &ui_hidden("shell", $ssh_shells[0]->{'shell'});
}
else {
print &ui_table_row(
&hlink($text{'user_ushell'}, "ushell"),
&available_shells_menu(
"shell", $user->{'shell'}, "owner"),
2, \@tds);
}
# Show secondary groups
my @sgroups = &allowed_secondary_groups($d);
if (@sgroups) {
print &ui_table_row(&hlink($text{'user_groups'},"usergroups"),
&ui_select("groups", $user->{'secs'},
[ map { [ $_ ] } @sgroups ], 5, 1, 1),
2, \@tds);
}
print &ui_hidden_table_end();
# Quota and home directory related fields
my $showquota = !$user->{'noquota'};
my $showhome = &can_mailbox_home($user) && $d && $d->{'home'} &&
!$user->{'fixedhome'};
if ($showquota || $showhome) {
# Start quota and home table
print &ui_hidden_table_start(
$text{'user_header2'}, "width=100%", 2, "table2", 1);
}
if ($showquota) {
# Show quotas field(s)
if (&has_home_quotas()) {
print &ui_table_row(
&hlink($qsame ? $text{'user_umquota'}
: $text{'user_uquota'}, "diskquota"),
"a_field("quota", $user->{'quota'},
$user->{'uquota'}, $user->{'ufquota'},
"home", $user),
2, \@tds);
}
if (&has_mail_quotas()) {
print &ui_table_row(
&hlink($text{'user_mquota'}, "diskmquota"),
"a_field("mquota", $user->{'mquota'},
$user->{'umquota'},$user->{'umfquota'},
"mail", $user),
2, \@tds);
}
}
if ($showhome) {
# Show home directory editing field
local $reshome = &resolve_links($user->{'home'});
local $helppage = "userhome";
if ($user->{'brokenhome'}) {
# Home directory is in odd location, and so cannot
# be edited
$homefield = "$user->{'home'}";
print &ui_hidden("brokenhome", 1),"\n";
}
else {
# Home is under server root, and so can be edited
$homefield = &ui_radio("home_def", 1 ? 1 : 0,
[ [ 1, $text{'user_home1'} ],
[ 0, &text('user_homeunder') ] ])." ".
&ui_textbox("home", "", 20);
}
print &ui_table_row(&hlink($text{'user_home'}, $helppage),
$homefield,
2, \@tds);
}
if ($showquota || $showhome) {
print &ui_hidden_table_end("table2");
}
}
# Create FTP user only form
elsif ($user_type eq 'ftp') {
&ui_print_header($din, $text{'user_createweb'}, "",
"users_explain_user_ftp");
$user = &create_initial_user($d, undef, 1);
# FTP user in a sub-server .. check if FTP restrictions are active
if ($user->{'webowner'} && $d->{'parent'} && $config{'ftp'}) {
my @chroots = &list_ftp_chroots();
my ($home) = grep { $_->{'dir'} eq '~' } @chroots;
if (!$home) {
print "$text{'user_chrootwarn'}
\n";
}
}
print &ui_form_start("save_user.cgi", "post");
print &ui_hidden("new", 1);
print &ui_hidden("dom", $in{'dom'});
print &ui_hidden("quota_def", 1);
print &ui_hidden("mquota_def", 1);
print &ui_hidden("recovery_def", 1);
print &ui_hidden('newmail_def', 1);
print &ui_hidden("web", 1);
print &ui_hidden("shell", '/bin/false');
print &ui_table_start(
$d ? $text{'user_header_ftp'} : $text{'user_lheader'},
"width=100%", 2);
# Edit mail username
print &ui_table_row(
&hlink($text{'user_user2'}, "username4_universal"),
&vui_noauto_textbox("mailuser", undef, 13).
($d ? "\@".&show_domain_name($d) : ""), 2, \@tds);
# Password cannot be edited for domain owners (because it is the
# domain pass)
$pwfield = &new_password_input("mailpass");
if (!$user->{'alwaysplain'}) {
# Option to disable
$pwfield .= "
" if ($pwfield !~ /\/table>/);
$pwfield .=
&ui_checkbox("disable", 1, $text{'user_disabled'},
$user->{'pass'} =~ /^\!/ ? 1 : 0);
}
print &ui_table_row(&hlink($text{'user_pass'}, "password"),
$pwfield,
2, \@tds);
# Real name
print &ui_table_row(
&hlink($text{'user_real'}, "realname"),
&vui_noauto_textbox("real", $user->{'real'}, 40),
2, \@tds);
# Show secondary groups
my @sgroups = &allowed_secondary_groups($d);
if (@sgroups) {
print &ui_table_row(&hlink($text{'user_groups'},"usergroups"),
&ui_select("groups", $user->{'secs'},
[ map { [ $_ ] } @sgroups ], 5, 1, 1),
2, \@tds);
}
# Show home directory editing field
my $showhome = &can_mailbox_home($user) && $d && $d->{'home'} &&
!$user->{'fixedhome'};
if ($showhome) {
if ($user->{'brokenhome'}) {
# Home directory is in odd location, and so cannot
# be edited
$homefield = "$user->{'home'}";
print &ui_hidden("brokenhome", 1),"\n";
}
elsif ($user->{'webowner'}) {
# Home can be public_html or a sub-dir
local $phd = &public_html_dir($d);
$homefield = &ui_radio("home_def", 1 ? 1 : 0,
[ [ 1, $text{'user_home2'} ],
[ 0, $text{'user_homeunder2'} ] ]).
" ".&ui_textbox("home", 1 ? "" :
substr($user->{'home'}, length($phd)+1), 20);
}
print &ui_table_row(&hlink($text{'user_home'}, 'userhomeftp'),
$homefield,
2, \@tds);
}
print &ui_table_end();
}
# Create Mail user only form
elsif ($user_type eq 'mail') {
$d->{'mail'} || &error($text{'users_ecannot3'});
&ui_print_header($din, $text{'user_createmail'}, "",
"users_explain_user_mail");
$user = &create_initial_user($d);
print &ui_form_start("save_user.cgi", "post");
print &ui_hidden("new", 1);
print &ui_hidden("dom", $in{'dom'});
print &ui_hidden("home_def", 1);
print &ui_hidden("shell", '/dev/null');
# Print quota hidden defaults as
# it has to be always considered
my $showquota = !$user->{'noquota'};
my $showhome = &can_mailbox_home($user) && $d && $d->{'home'} &&
!$user->{'fixedhome'};
if ($showquota) {
if (&has_home_quotas()) {
my $quota_data = "a_field(
"quota", $user->{'quota'}, $user->{'uquota'},
$user->{'ufquota'}, "home", $user);
print &vui_hidden($quota_data);
}
if (&has_mail_quotas()) {
my $mquota_data = "a_field(
"mquota", $user->{'mquota'}, $user->{'umquota'},
$user->{'umfquota'}, "mail", $user);
print &vui_hidden($mquota_data);
}
}
# Show accordions
print &ui_hidden_table_start(
$d ? $text{'user_header_mail'} : $text{'user_lheader'},
"width=100%", 2, "table1", 1);
# Edit mail username
print &ui_table_row(
&hlink($text{'user_user'}, "username_universal"),
&vui_noauto_textbox("mailuser", undef, 13).
($d ? "\@".&show_domain_name($d) : ""),
2, \@tds);
# Password field
$pwfield = &new_password_input("mailpass");
if (!$user->{'alwaysplain'}) {
# Option to disable
$pwfield .= "
" if ($pwfield !~ /\/table>/);
$pwfield .=
&ui_checkbox("disable", 1, $text{'user_disabled'},
$user->{'pass'} =~ /^\!/ ? 1 : 0);
}
print &ui_table_row(&hlink($text{'user_pass'}, "password"),
$pwfield,
2, \@tds);
# Password recovery field
print &ui_table_row(&hlink($text{'user_recovery'}, "recovery"),
&ui_opt_textbox("recovery", $user->{'recovery'}, 40,
$text{'user_norecovery'},
$text{'user_gotrecovery'}));
# Real name
print &ui_table_row(
&hlink($text{'user_real'}, "realname"),
&vui_noauto_textbox("real", $user->{'real'}, 40),
2, \@tds);
print &ui_hidden_table_end();
# Start third table, for email settings
$hasprimary = $d && !$user->{'noprimary'} && $d->{'mail'};
$hasextra = !$user->{'noextra'};
$hassend = &will_send_user_email($d, 1);
$hasspam = $config{'spam'} && $hasprimary;
$hasemail = $hasprimary || $hasextra ||
$hassend || $hasspam;
# Email settings
if ($hasemail) {
print &ui_hidden_table_start(
$text{'user_header3'}, "width=100%", 2, "table2a", 0);
}
if ($hasprimary) {
# Show primary email address field
print &ui_table_row(&hlink($text{'user_mailbox'}, "mailbox"),
&ui_yesno_radio("mailbox", 1),
2, \@tds);
}
if ($hasextra) {
# Show extra email addresses
@extra = @{$user->{'extraemail'}};
foreach $e (@extra) {
if ($e =~ /^(\S*)\@(\S+)$/) {
local ($eu, $ed) = ($1, $2);
$ed = &show_domain_name($ed);
$e = $eu."\@".$ed;
}
}
print &ui_table_row(&hlink($text{'user_extra'}, "extraemail"),
&ui_textarea("extra", join("\n", @extra), 5, 50),
2, \@tds);
}
if (&will_send_user_email($d, 1)) {
# Show address for confirmation email (for the mailbox itself)
print &ui_table_row(&hlink($text{'user_newmail'},"newmail"),
&ui_opt_textbox("newmail", undef, 40,
$user->{'email'} ? $text{'user_newmail1'}
: $text{'user_newmail2'},
$text{'user_newmail0'}),
2, \@tds);
}
# Show spam check flag
if ($hasspam) {
print &ui_table_row(
&hlink($d->{'virus'} ? $text{'user_nospam'}
: $text{'user_nospam2'}, "nospam"),
!$d->{'spam'} ? $text{'user_spamdis'} :
&ui_radio("nospam", int($user->{'nospam'}),
[ [ 0, $text{'yes'} ], [ 1, $text{'no'} ] ]),
2, \@tds);
}
if ($hasemail) {
# Show forwarding setup for this user, using simple form
# if possible
if (($user->{'email'} || $user->{'noprimary'}) &&
!$user->{'noalias'}) {
print &ui_table_hr();
# Work out if simple mode is supported
if (!@{$user->{'to'}}) {
# If no forwarding, just check delivery to me
# as this is the default.
$simple = { 'tome' => 1 };
}
else {
$simple = &get_simple_alias($d, $user, 1);
}
if ($simple && ($simple->{'local'} || $simple->{'bounce'})) {
# Local and bounce delivery are not allowed on
# the simple form, unless we can merge some
# (@) local users with forward users, which
# will be handled automatically on save to
# prevent showing advanced form for no reason
$simple = undef if (!$simple->{'local-all'} ||
$simple->{'bounce'});
}
if ($simple) {
# Show simple form
print &ui_hidden("simplemode", "simple");
&show_simple_form(
$simple, 1, 1, 1, 1, \@tds, "user");
}
else {
# Show complex form
print &ui_hidden("simplemode", "complex");
&alias_form($user->{'to'},
&hlink($text{'user_aliases'}, "userdest"),
$d, "user", $in{'user'}, \@tds);
}
}
# Show user-level mail filters, if he has any
@filters = ( );
if (@filters) {
my $mail_filter_title = $text{'user_header3a'};
my $mail_filter_body;
$lastalways = 0;
@folders = &mailboxes::list_user_folders(
$user->{'user'});
@table = ( );
foreach $filter (@filters) {
($cdesc, $lastalways) =
&filter::describe_condition($filter);
$adesc = &filter::describe_action(
$filter, \@folders, $user->{'home'});
push(@table, [ $cdesc, $adesc ]);
}
if (!$lastalways) {
push(@table, [ $filter::text{'index_calways'},
$filter::text{'index_adefault'} ]);
}
$mail_filter_body = &ui_columns_table(
[ $text{'user_fcondition'},
$text{'user_faction'} ],
100,
\@table);
my $mail_filter_details = &ui_details({
'title' => $mail_filter_title,
'content' => $mail_filter_body,
'class' =>'default',
'html' => 1});
print &ui_table_row(
undef, $mail_filter_details, 2,
undef, ["data-row-wrapper='details'"]);
}
print &ui_hidden_table_end("table2a");
}
}
# Create database user only form
elsif ($user_type eq 'db') {
&ui_print_header(
$din, $text{$in{'new'} ? 'user_createdb' : 'user_edit'}, "",
$in{'new'} ? 'users_explain_user_db' : undef);
$user = &create_initial_user($d);
&list_extra_user_pro_tip('db', "list_users.cgi?dom=$in{'dom'}");
print &ui_form_start("pro/save_user_db.cgi", "post");
print &ui_hidden("new", $in{'new'});
print &ui_hidden("olduser", $in{'user'});
print &ui_hidden("dom", $in{'dom'});
my $dbuser;
my $dbuser_name;
if (!$in{'new'}) {
$dbuser = &get_extra_db_user($d, $in{'user'});
$dbuser || &error(&text('user_edoesntexist',
&html_escape($in{'user'})));
$dbuser_name = &remove_userdom(
$dbuser->{'user'}, $d) || $dbuser->{'user'};
}
print &ui_table_start($text{'user_header_db'}, "width=100%", 2);
# Show current full username
if (!$in{'new'}) {
print &ui_table_row(
&hlink($text{'user_user3'}, "username3"),
"$dbuser->{'user'}", 2, \@tds);
}
# Edit db user
print &ui_table_row(&hlink($text{'user_user2'}, "username_db"),
&inline_html_pro_tip(
&vui_noauto_textbox("dbuser", $dbuser_name, 15).
($d ? "\@".&show_domain_name($d) : ""),
'manage-extra-database-users', 1),
2, &procell(undef, @tds) || \@tds);
# Edit password
my $pwfield = &new_password_input("dbpass");
if (!$in{'new'}) {
# For existing user show password field
$pwfield = &ui_opt_textbox("dbpass", undef, 15,
$text{'user_passdef'},
$text{'user_passset'});
}
print &ui_table_row(&hlink($text{'user_pass'}, "password"),
&inline_html_pro_tip($pwfield,
'manage-extra-database-users', 1),
2, &procell(undef, @tds) || \@tds);
# Show allowed databases
my @dbs = grep { $_->{'users'} } &domain_databases($d) if ($d);
if (@dbs) {
print &ui_table_hr();
my @idbs = $in{'new'} ? @{$user->{'dbs'}} : @{$dbuser->{'dbs'}};
@userdbs = map { [ $_->{'type'}."_".$_->{'name'},
$_->{'name'}." ($_->{'desc'})" ] } @idbs;
@alldbs = map { [ $_->{'type'}."_".$_->{'name'},
$_->{'name'}." ($_->{'desc'})" ] } @dbs;
print &ui_table_row(&hlink($text{'user_dbs'},"userdbs"),
&ui_multi_select("dbs", \@userdbs, \@alldbs, 5, 1, 0,
$text{'user_dbsall'}, $text{'user_dbssel'}),
2, &procell(2));
}
print &ui_table_end();
}
# Create web user only form
elsif ($user_type eq 'web') {
&ui_print_header(
$din, $text{$in{'new'} ? 'user_createwebserver' : 'user_edit'}, "",
$in{'new'} ? 'users_explain_user_web' : undef);
&list_extra_user_pro_tip('web', "list_users.cgi?dom=$in{'dom'}");
print &ui_form_start("pro/save_user_web.cgi", "post");
print &ui_hidden("new", $in{'new'});
print &ui_hidden("olduser", $in{'user'});
print &ui_hidden("dom", $in{'dom'});
my $webuser = &create_initial_user($d);
my $webuser_name;
if (!$in{'new'}) {
$webuser = &get_extra_web_user($d, $in{'user'});
$webuser || &error(&text('user_edoesntexist',
&html_escape($in{'user'})));
$webuser_name = &remove_userdom($webuser->{'user'}, $d) ||
$webuser->{'user'};
}
# At first check if we have protected webdirectories in this domain
my $htpasswd_data;
foreach my $f (&list_mail_plugins()) {
if ($f eq "virtualmin-htpasswd") {
$input = &trim(&plugin_call($f, "mailbox_inputs",
$webuser, $in{'new'}, $d));
$htpasswd_data = $input if ($input);
last;
}
}
# Print protected directories selector if found
if ($htpasswd_data) {
print &ui_table_start(
$text{'user_header_webserver'}, "width=100%", 2);
# Show current full username
if (!$in{'new'}) {
print &ui_table_row(
&hlink($text{'user_user3'}, "username3"),
"$webuser->{'user'}", 2, \@tds);
}
# Edit web user
print &ui_table_row(&hlink($text{'user_user2'}, "username_web"),
&inline_html_pro_tip(
&vui_noauto_textbox("webuser", $webuser_name, 15).
($d ? "\@".&show_domain_name($d) : ""),
'manage-extra-webserver-users', 1),
2, &procell(undef, @tds) || \@tds);
# Edit password
my $pwfield = &new_password_input("webpass", 0);
if (!$in{'new'}) {
# For existing user show password field
$pwfield = &ui_opt_textbox("webpass", undef, 15,
$text{'user_passdef'},
$text{'user_passset'}, 0);
}
print &ui_table_row(
&hlink($text{'user_pass'}, "password"),
&inline_html_pro_tip(
$pwfield, 'manage-extra-webserver-users', 1),
2, &procell(undef, @tds) || \@tds);
print &ui_table_hr();
print $htpasswd_data;
my $msg = &text('users_addprotecteddir2',
&get_webprefix().
"/virtualmin-htpasswd/index.cgi?dom=$d->{'id'}");
print &ui_table_row("", $msg, 1);
print &ui_table_end();
}
else {
print &ui_alert_box(
&text('users_addprotecteddir',
&get_webprefix().
"/virtualmin-htpasswd/index.cgi?dom=$d->{'id'}"),
'info');
}
$form_end = $htpasswd_data ? 1 : 0;
}
else {
# Regular create or edit user form
if ($in{'new'}) {
&ui_print_header(
$din, $text{'user_create'}, "", "users_explain_user");
$user = &create_initial_user($d);
}
else {
@users = &list_domain_users($d);
($user) = grep {
($_->{'user'} eq $in{'user'} ||
&remove_userdom($_->{'user'}, $d) eq $in{'user'})
} @users;
$mailbox = $d && $d->{'user'} eq $user->{'user'};
$suffix = $user->{'webowner'} ? 'web' : '';
&ui_print_header($din, $text{'user_edit'.$suffix}, "");
}
$shell_switch = ((&can_mailbox_ftp() && !$mailbox) || &master_admin())&&
!$user->{'webowner'};
@sgroups = &allowed_secondary_groups($d);
# Work out if the other permissions section has anything to display
if ($d && !$mailbox) {
@dbs = grep { $_->{'users'} } &domain_databases($d);
}
# FTP user in a sub-server .. check if FTP restrictions are active
if ($user->{'webowner'} && $d->{'parent'} && $config{'ftp'}) {
my @chroots = &list_ftp_chroots();
my ($home) = grep { $_->{'dir'} eq '~' } @chroots;
if (!$home) {
print "$text{'user_chrootwarn'}
\n";
}
}
print &ui_form_start("save_user.cgi", "post");
print &ui_hidden("new", $in{'new'});
print &ui_hidden("dom", $in{'dom'});
print &ui_hidden("old", $in{'user'});
print &ui_hidden("web", $in{'web'});
print &ui_hidden_table_start(
$mailbox ? $text{'user_mheader'} :
$user->{'webowner'} ? $text{'user_header_ftp'} :
$d ? $text{'user_header'} : $text{'user_lheader'},
"width=100%", 2, "table1", 1);
# Show username, editable if this is not the domain owner
$ulabel = ($d->{'mail'} && !$user->{'webowner'}) ?
&hlink($text{'user_user'}, "username_universal") :
&hlink($text{'user_user2'}, "username2_universal");
if ($in{'new'}) {
$ulabel = &hlink($text{'user_user3'},
($user->{'webowner'} ? 'username4' : 'username3').
"_universal");
}
if ($user->{'webowner'}) {
$ulabel = &hlink($text{'user_user2'}, "username4_universal");
}
if ($mailbox) {
# Domain owner
my $ouser_email = $user->{'user'};
if ($d->{'mail'} && $ouser_email !~ /\@/) {
$ouser_email = $user->{'user'} . "\@" . $d->{'dom'};
}
print &ui_table_row(
&hlink($text{'user_user2'}, "username2_universal"),
"$user->{'user'}", 2, \@tds);
print &ui_table_row($ulabel, "$ouser_email", 2, \@tds)
if ($d->{'mail'});
$pop3 = $user->{'user'};
}
else {
# Regular user
$pop3 = $d && !$user->{'noappend'} ?
&remove_userdom($user->{'user'}, $d) : $user->{'user'};
# Full username differs
if ($pop3 ne $user->{'user'}) {
print &ui_table_row(
&hlink($text{"user_user3"},
$user->{'webowner'} ? 'username4' : 'username3'),
"$user->{'user'}");
}
# Edit mail username
print &ui_table_row($ulabel,
&ui_textbox("mailuser", $pop3, 13, 0, undef,
&vui_ui_input_noauto_attrs()).
($d ? "\@".&show_domain_name($d) : ""),
2, \@tds);
print &ui_hidden("oldpop3", $pop3),"\n";
}
# Password cannot be edited for domain owners (because it is the
# domain pass)
if (!$mailbox) {
$pwfield = "";
if ($in{'new'}) {
$pwfield = &new_password_input("mailpass");
}
else {
# For an existing user, offer to change password
$pwfield = &ui_opt_textbox("mailpass", undef, 13,
$text{'user_passdef'}."\n".
(defined($user->{'plainpass'}) ?
&show_password_popup($d, $user) : ""),
$text{'user_passset'});
if ($user->{'change'}) {
local $tm = timelocal(gmtime($user->{'change'} *
60*60*24));
$pwfield .= " ".
&text('user_lastch', &make_date($tm, 1));
}
}
if (!$user->{'alwaysplain'}) {
# Option to disable
$pwfield .= "
" if ($pwfield !~ /\/table>/);
$pwfield .= &ui_checkbox(
"disable", 1, $text{'user_disabled'},
$user->{'pass'} =~ /^\!/ ? 1 : 0);
}
print &ui_table_row(&hlink($text{'user_pass'}, "password"),
$pwfield,
2, \@tds);
# SSH public key for Unix user
if (&proshow()) {
my $existing_key = &get_domain_user_ssh_pubkey($d, $user);
my $existing_key_hidden;
if ($existing_key && !$virtualmin_pro) {
$existing_key_hidden =
&ui_hidden("sshkey", $existing_key).
&ui_hidden("sshkey_mode", 2);
}
print &ui_table_row(&hlink($text{'form_sshkey'}, "sshkeynogen"),
&inline_html_pro_tip(
&ui_radio("sshkey_mode", $existing_key ? 2 : 0,
[ [ 0, $text{'form_sshkey0'} ],
[ 2, $text{'form_sshkey2'} ] ]),
'manage-user-ssh-public-key').
"
\n". &ui_textarea("sshkey", $existing_key, 3, 60,
undef, !$virtualmin_pro, &vui_ui_input_noauto_attrs()).
$existing_key_hidden,
undef, &procell() || \@tds);
}
# Password recovery field
if (!$user->{'webowner'}) {
print &ui_table_row(
&hlink($text{'user_recovery'}, "recovery"),
&ui_opt_textbox(
"recovery", $user->{'recovery'}, 40,
$text{'user_norecovery'},
$text{'user_gotrecovery'}));
}
}
# Real name - only for show for mailbox users
if (!$mailbox || $user->{'real'}) {
print &ui_table_row(
&hlink($text{'user_real'}, "realname"),
$mailbox ? $user->{'real'} :
&ui_textbox("real", $user->{'real'}, 40, 0,
undef, &vui_ui_input_noauto_attrs()),
2, \@tds);
}
# Show FTP shell field
if ($shell_switch) {
my $user_shell;
if ($in{'new'}) {
# For the new user fall-back to the no login shell
my @ftp_shell =
grep { $_->{'id'} eq 'ftp' && $_->{'avail'} }
&list_available_shells($d);
if (@ftp_shell) {
$user_shell = $ftp_shell[0]->{'shell'};
}
}
else {
$user_shell = $user->{'shell'};
}
print &ui_table_row(&hlink($text{'user_ushell'}, "ushell"),
&available_shells_menu("shell", $user_shell, "mailbox",
$user->{'webowner'} ? 'ftp' : undef),
2, \@tds);
}
# Show secondary groups
if (@sgroups) {
print &ui_table_row(&hlink($text{'user_groups'},"usergroups"),
&ui_select("groups", $user->{'secs'},
[ map { [ $_ ] } @sgroups ], 5, 1, 1),
2, \@tds);
}
print &ui_hidden_table_end();
$showquota = !$mailbox && !$user->{'noquota'};
$showhome = &can_mailbox_home($user) && $d && $d->{'home'} &&
!$mailbox && !$user->{'fixedhome'};
if ($showquota || $showhome) {
# Start quota and home table
my $header2_title = 'user_header2';
$header2_title = 'user_header2a' if (!$showhome);
$header2_title = 'user_header2b' if (!$showquota);
print &ui_hidden_table_start(
$text{$header2_title}, "width=100%", 2, "table2", 0);
}
if ($showquota) {
# Show quotas field(s)
if (&has_home_quotas()) {
print &ui_table_row(
&hlink($qsame ? $text{'user_umquota'}
: $text{'user_uquota'}, "diskquota"),
"a_field("quota", $user->{'quota'},
$user->{'uquota'}, $user->{'ufquota'},
"home", $user),
2, \@tds);
}
if (&has_mail_quotas()) {
print &ui_table_row(
&hlink($text{'user_mquota'}, "diskmquota"),
"a_field("mquota", $user->{'mquota'},
$user->{'umquota'},
$user->{'umfquota'}, "mail",$user),
2, \@tds);
}
}
if ($showhome) {
# Show home directory editing field
local $reshome = &resolve_links($user->{'home'});
local $helppage = "userhome";
if ($user->{'brokenhome'}) {
# Home directory is in odd location, and so cannot
# be edited
$homefield = "$user->{'home'}";
print &ui_hidden("brokenhome", 1),"\n";
}
elsif ($user->{'webowner'}) {
# Home can be public_html or a sub-dir
local $phd = &public_html_dir($d);
local $auto = $in{'new'} ||
$reshome eq &resolve_links($phd);
$homefield = &ui_radio("home_def", $auto ? 1 : 0,
[ [ 1, $text{'user_home2'} ],
[ 0, $text{'user_homeunder2'} ] ]).
" ".
&ui_textbox("home", $auto ? "" :
substr($user->{'home'}, length($phd)+1), 20);
$helppage = "userhomeftp";
}
else {
# Home is under server root, and so can be edited
local $auto = $in{'new'} ||
$reshome eq
&resolve_links("$d->{'home'}/$config{'homes_dir'}/$pop3");
$homefield = &ui_radio("home_def", $auto ? 1 : 0,
[ [ 1, $text{'user_home1'} ],
[ 0, &text('user_homeunder') ] ])." ".
&ui_textbox("home", $auto ? "" :
substr($user->{'home'}, length($d->{'home'})+1), 20);
}
print &ui_table_row(&hlink($text{'user_home'}, $helppage),
$homefield,
2, \@tds);
}
if ($showquota || $showhome) {
print &ui_hidden_table_end("table2");
}
# Start third table, for email settings
$hasprimary = $d && !$user->{'noprimary'} && $d->{'mail'};
$hasmailfile = !$in{'new'} && ($user->{'email'} ||
@{$user->{'extraemail'}}) && !$user->{'nomailfile'};
$hasextra = !$user->{'noextra'};
$hassend = &will_send_user_email($d, $in{'new'});
$hasspam = $config{'spam'} && $hasprimary;
$hasemail = $hasprimary || $hasmailfile || $hasextra ||
$hassend || $hasspam;
$hasemailaccordion = !$user->{'webowner'} && $d->{'mail'};
# Email settings
if ($hasemailaccordion) {
if ($hasemail && $d->{'mail'}) {
print &ui_hidden_table_start(
$text{'user_header3'}, "width=100%", 2, "table2a", 0);
}
if ($hasprimary) {
# Show primary email address field
print &ui_table_row(
&hlink($text{'user_mailbox'}, "mailbox"),
&ui_yesno_radio("mailbox",
$user->{'email'} || $in{'new'} ? 1 : 0),
2, \@tds);
}
if ($hasmailfile && $config{'show_mailuser'}) {
# Show the user's mail file
local ($sz, $umf, $lastmod) = &mail_file_size($user);
local $link = &read_mail_link($user, $d);
if ($link) {
$mffield = "$umf\n";
}
else {
$mffield = "$umf\n";
}
if ($lastmod) {
$mffield .= "(".&text('user_lastmod',
&make_date($lastmod)).")";
}
if ($user->{'spam_quota'}) {
$mffield .= "
".
&text($user->{'spam_quota_diff'} ? 'user_spamquota'
: 'user_soamquota2',
&nice_size($user->{'spam_quota_diff'})).
"\n";
}
print &ui_table_row(&hlink($text{'user_mail'}, "mailfile"),
$mffield, 2, \@tds);
}
if ($hasextra) {
# Show extra email addresses
@extra = @{$user->{'extraemail'}};
foreach $e (@extra) {
if ($e =~ /^(\S*)\@(\S+)$/) {
local ($eu, $ed) = ($1, $2);
$ed = &show_domain_name($ed);
$e = $eu."\@".$ed;
}
}
print &ui_table_row(
&hlink($text{'user_extra'}, "extraemail"),
&ui_textarea("extra", join("\n", @extra), 5, 50),
2, \@tds);
}
if ($in{'new'} && &will_send_user_email($d, 1)) {
# Show address for confirmation email (for the mailbox
# itself)
print &ui_table_row(
&hlink($text{'user_newmail'},"newmail"),
&ui_opt_textbox("newmail", undef, 40,
$user->{'email'} ? $text{'user_newmail1'}
: $text{'user_newmail2'},
$text{'user_newmail0'}),
2, \@tds);
}
elsif (!$in{'new'} && &will_send_user_email($d, 0)) {
# Show option to re-send info email
print &ui_table_row(
&hlink($text{'user_remail'},"remail"),
&ui_radio("remail_def", 1,
[ [ 1, $text{'user_remail1'} ],
[ 0, $text{'user_remail0'} ] ])." ".
&ui_textbox("remail", $user->{'email'}, 40),
2, \@tds);
}
# Show spam check flag
if ($hasspam) {
$awl_link = undef;
if (!$in{'new'} && &foreign_available("spam")) {
# Create AWL link
&foreign_require("spam");
if (defined(&spam::can_edit_awl) &&
&spam::supports_auto_whitelist() == 2 &&
&spam::get_auto_whitelist_file($user->{'user'}) &&
&spam::can_edit_awl($user->{'user'})) {
$awl_link = " ( $text{'user_awl'} )";
}
}
print &ui_table_row(
&hlink($d->{'virus'} ? $text{'user_nospam'} :
$text{'user_nospam2'}, "nospam"),
!$d->{'spam'} ? $text{'user_spamdis'} :
&ui_radio("nospam",
int($user->{'nospam'}),
[ [ 0, $text{'yes'} ],
[ 1, $text{'no'} ] ]).
$awl_link,
2, \@tds);
}
# Show most recent logins
if ($hasemail && !$in{'new'}) {
$ll = &get_last_login_time($user->{'user'});
@grid = ( );
foreach $k (keys %$ll) {
push(@grid, $text{'user_lastlogin_'.$k},
&make_date($ll->{$k}));
}
print &ui_table_row(
&hlink($text{'user_lastlogin'}, "lastlogin"),
@grid ? &ui_grid_table(\@grid, 2, 50)
: $text{'user_lastlogin_never'});
}
if ($hasemail) {
# Show forwarding setup for this user, using
# simple form if possible
if (($user->{'email'} || $user->{'noprimary'}) &&
!$user->{'noalias'}) {
print &ui_table_hr();
# Work out if simple mode is supported
if (!@{$user->{'to'}}) {
# If no forwarding, just check delivery
# to me as this is the default.
$simple = { 'tome' => 1 };
}
else {
$simple = &get_simple_alias(
$d, $user, 1);
}
if ($simple && ($simple->{'local'} ||
$simple->{'bounce'})) {
# Local and bounce delivery are not allowed on the simple form,
# unless we can merge some (@) local users with forward users,
# which will be handled automatically on save to prevent showing
# advanced form for no reason
$simple = undef
if (!$simple->{'local-all'} || $simple->{'bounce'});
}
if ($simple) {
# Show simple form
print &ui_hidden("simplemode", "simple");
&show_simple_form($simple, 1, 1, 1, 1, \@tds, "user");
}
else {
# Show complex form
print &ui_hidden("simplemode", "complex");
&alias_form($user->{'to'},
&hlink($text{'user_aliases'}, "userdest"),
$d, "user", $in{'user'}, \@tds);
}
}
# Show user-level mail filters, if he has any
@filters = ( );
$procmailrc = "$user->{'home'}/.procmailrc" if (!$in{'new'});
if (!$in{'new'} && $user->{'email'} && -r $procmailrc &&
&foreign_check("filter")) {
&foreign_require("filter");
@filters = &filter::list_filters($procmailrc);
}
if (@filters) {
my $mail_filter_title = $text{'user_header3a'};
my $mail_filter_body;
$lastalways = 0;
@folders = &mailboxes::list_user_folders($user->{'user'});
@table = ( );
foreach $filter (@filters) {
($cdesc, $lastalways) = &filter::describe_condition($filter);
$adesc = &filter::describe_action($filter, \@folders,
$user->{'home'});
push(@table, [ $cdesc, $adesc ]);
}
if (!$lastalways) {
push(@table, [ $filter::text{'index_calways'},
$filter::text{'index_adefault'} ]);
}
$mail_filter_body = &ui_columns_table(
[ $text{'user_fcondition'}, $text{'user_faction'} ],
100,
\@table);
my $mail_filter_details = &ui_details({
'title' => $mail_filter_title,
'content' => $mail_filter_body,
'class' =>'default',
'html' => 1});
print &ui_table_row(undef, $mail_filter_details, 2, undef, ["data-row-wrapper='details'"]);
}
print &ui_hidden_table_end("table2a");
}
}
# Cache the list of available mail plugins
my @list_mail_plugins = &list_mail_plugins();
# Test available plugins first
foreach my $f (@list_mail_plugins) {
if ($f eq "virtualmin-htpasswd") {
$htpasswdplugin++;
}
else {
$anyotherplugins++
if (&plugin_defined($f, "mailbox_inputs"));
}
}
# Put user databases select under separate category
if (@dbs) {
# Show allowed databases
print &ui_hidden_table_start(
$text{'user_header4'}, "width=100%", 2,
"table4", 0, \@tds);
@userdbs = map { [ $_->{'type'}."_".$_->{'name'},
$_->{'name'}." ($_->{'desc'})" ] }
@{$user->{'dbs'}};
@alldbs = map { [ $_->{'type'}."_".$_->{'name'},
$_->{'name'}." ($_->{'desc'})" ] } @dbs;
print &ui_table_row(&hlink($text{'user_dbs'},"userdbs"),
&ui_multi_select("dbs", \@userdbs, \@alldbs, 5, 1, 0,
$text{'user_dbsall'}, $text{'user_dbssel'}), 2, \@tds);
print &ui_hidden_table_end("table4");
}
# Put htpasswd into separate category for clarity
if ($htpasswdplugin) {
print &ui_hidden_table_start(
$text{'user_header5'}, "width=100%", 2,
"table5", 0, \@tds);
foreach my $f (@list_mail_plugins) {
if ($f eq "virtualmin-htpasswd") {
$input = &plugin_call($f, "mailbox_inputs",
$user, $in{'new'}, $d);
print $input;
my $msg = &text('users_addprotecteddir2',
&get_webprefix()."/virtualmin-htpasswd/index.cgi?dom=$d->{'id'}");
print &ui_table_row("", $msg, 1);
last;
}
}
print &ui_hidden_table_end("table5");
}
# Other plugins permissions settings
# Find and show all plugin features
foreach my $f (@list_mail_plugins) {
if ($f ne "virtualmin-htpasswd") {
my $input = &trim(&plugin_call($f, "mailbox_inputs",
$user, $in{'new'}, $d));
if ($input) {
$anyotherpluginsdata .= &ui_table_hr()
if ($list_mail_plugin++);
$anyotherpluginsdata .= $input;
}
}
}
if ($anyotherplugins && $anyotherpluginsdata) {
print &ui_hidden_table_start($text{'user_header6'},
"width=100%", 2, "table6", 0, \@tds);
print $anyotherpluginsdata;
print &ui_hidden_table_end("table6");
}
# Work out if switching to Usermin is allowed
$usermin = 0;
if (&can_switch_usermin($d, $user) &&
&foreign_installed("usermin", 1)) {
&foreign_require("usermin");
local %uminiserv;
&usermin::get_usermin_miniserv_config(\%uminiserv);
if (&check_pid_file($uminiserv{'pidfile'}) &&
defined(&usermin::switch_to_usermin_user) &&
$uminiserv{'session'}) {
$usermin = 1;
}
}
}
# Form create/delete buttons
if ($form_end) {
if ($in{'new'}) {
print &ui_form_end(
[ [ "create", $text{'create'} ] ]);
}
else {
print &ui_form_end(
[ [ "save", $text{'save'} ],
$usermin ? ( [ "switch", $text{'user_switch'}, undef, undef,
"onClick='form.target = \"_blank\"'" ] ) : ( ),
&will_send_user_email($d) && $user->{'email'} ?
( [ "remailbut", $text{'user_remailbut'} ] ) : ( ),
$user->{'recovery'} ?
( [ "recoverybut", $text{'user_sendrecover'} ] ) : ( ),
$mailbox ? ( ) : ( [ "delete", $text{'delete'} ] ) ]);
}
}
# Link back to user list and/or main menu
if ($d) {
if ($single_domain_mode) {
&ui_print_footer(
"list_users.cgi?dom=$in{'dom'}", $text{'users_return'},
"", $text{'index_return2'});
}
else {
&ui_print_footer(
"list_users.cgi?dom=$in{'dom'}", $text{'users_return'},
&domain_footer_link($d),
"", $text{'index_return'});
}
}
else {
&ui_print_footer("", $text{'index_return'});
}